package com.ynding.cloud.auth.authentication.service.impl;

import com.ynding.cloud.auth.api.admin.api.IUserApiService;
import com.ynding.cloud.auth.api.authentication.model.bo.AccessToken;
import com.ynding.cloud.auth.api.authentication.model.bo.AppInfo;
import com.ynding.cloud.auth.authentication.service.IRegLoginService;
import com.ynding.cloud.auth.authentication.utils.Md5Util;
import com.ynding.cloud.common.dict.CloudServiceInfo;
import com.ynding.cloud.common.model.bo.AuthConstants;
import com.ynding.cloud.common.model.bo.ResponseBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

/**
 * <p> </p>
 *
 * @author ynding
 * @version 2021/9/10
 **/
@Service
@Slf4j
public class RegLoginServiceImpl implements IRegLoginService {

    @DubboReference
    private IUserApiService userService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public String getToken(String username, String password) {
        //获取token的url
//        String tokenUrl = "http://localhost:10402/oauth/token";
        ServiceInstance serviceInstance = loadBalancerClient.choose(CloudServiceInfo.AUTH_SERVER_AUTHENTICATION);
        URI uri = serviceInstance.getUri();
        String tokenUrl = uri + "/oauth/token";
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        // Perform the security
//        final Authentication authentication = authenticationManager.authenticate(upToken);
//        SecurityContextHolder.getContext().setAuthentication(authentication);
        // Reload password post-security so we can generate token
        final UserDetails userDetails = userService.loadUserByUsername(username);
        // 持久化的redis
        HttpHeaders headers = new HttpHeaders();
        headers.setBasicAuth(AppInfo.APP_ID, AppInfo.APP_SECRET);
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        // 设置请求体
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("username", username);
        map.add("password", password);
        map.add("grant_type", "password");
        map.add("scope", "read write");
        // 用HttpEntity封装整个请求报文
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        ResponseEntity<AccessToken> response = restTemplate.exchange(tokenUrl, HttpMethod.POST, request, AccessToken.class);
        String token = response.getBody().getAccess_token();
        redisTemplate.opsForValue().set(token, userDetails.getUsername());
        return token;
    }

    @Override
    public ResponseBean userReg(String username, String password) {
        String encode = passwordEncoder.encode(password);
        return userService.userReg(username, encode);
    }


    /**
     * 登陆与授权.（简单版）
     *
     * @param username .
     * @param password .
     * @return
     */
    private String generateToken(String username, String password) {
        UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(username, password);
        // Perform the security
        final Authentication authentication = authenticationManager.authenticate(upToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // Reload password post-security so we can generate token
        final UserDetails userDetails = userService.loadUserByUsername(username);
        // 持久化的redis
        String token = AuthConstants.JWT_TOKEN_PREFIX + Md5Util.stringToMD5(userDetails.getUsername());
        redisTemplate.opsForValue().set(token, userDetails.getUsername());
        return token;
    }

}
